module ysyx_050369_ex (
    input           clk,
    input           rst,
    //
    input           ex_valid,
    input           ex_ready,
    output          ex2as_valid,
    input           id2ex_valid,         
    //          
    input   [31:0]  i_pc,
    input   [31:0]  i_inst,
    input   [31:0]  i_pre_pc,
    input           i_pre_jump,
    
    //from id
    input   [63:0]  i_src1,
    input   [63:0]  i_src2, 
    input   [4 :0]  i_reg_waddr,
    input           i_RegWr,
    input           i_ALUAsrc,
    input    [2:0]  i_ALUBsrc,
    input    [5:0]  i_ALUctr,
    input    [2:0]  i_Branch,
    input           i_MemtoReg,
    input           i_MemWr,
    input    [63:0] i_imm,
    input    [7:0]  i_rmask,
    input    [7:0]  i_wmask,
    input           i_csr_wen,
    //to ctrl
    output  [1:0]   o_ex_fence_i,
    input           i_dcache_done,
    output          o_mret_flag,
    output          o_ecall_flag,

    //to reg-file
    output  [31:0]  o_pc,
    output  [31:0]  o_inst,
    output          o_reg_wen,
    output  [4 :0]  o_reg_waddr,
    output  [63:0]  o_reg_res,
    output          o_ALU_busy,
    //to cseg
    input   [63:0]  i_csr_rdata,
    output          o_csr_wen,
    output  [11:0]  o_csr_waddr,
    output  [63:0]  o_csr_wdata,
    
    //to pc
    output          o_jump_valid,
    output          pre_error,
    output   [31:0] o_nxpc,
    output          o_mem_wen,
    output   [31:0] o_mem_waddr,
    output   [63:0] o_mem_wdata,
    output   [7 :0] o_mem_wmask,
    output          o_mem_ren,
    output   [31:0] o_mem_raddr,
    output   [7 :0] o_mem_rmask
    

);
    assign ex2as_valid = ex_valid;


    reg   [31:0]  pc;
    reg   [31:0]  inst;
    reg           stop;
    //from id
    reg   [31:0]  pre_pc;
    reg           pre_jump;
    reg   [63:0]  src1;
    reg   [63:0]  src2; 
    reg   [4 :0]  reg_waddr;
    reg           RegWr;
    reg           ALUAsrc;
    reg    [2:0]  ALUBsrc;
    reg    [5:0]  ALUctr ;
    reg    [2:0]  Branch;
    reg           MemtoReg;
    reg           MemWr;
    reg    [63:0] imm;
    reg    [7:0]  rmask;
    reg    [7:0]  wmask;
    reg           csr_wen;
    reg    [63:0] csr_rdata;
    reg    [31:0] nxpc;
    wire          jump_valid;
    always @(posedge clk )begin
        if (rst) begin
            pc        <= 32'b0;
            inst      <= 32'b0;
            reg_waddr <= 5'b0;
            src1      <= 'b0;
            src2      <= 'b0;
            RegWr     <= 1'b0;
            ALUAsrc   <= 1'b0;
            ALUBsrc   <= 3'b0;
            ALUctr    <= 6'b0;
            Branch    <= 3'b0;
            MemtoReg  <= 1'b0;
            MemWr     <= 1'b0;
            imm       <= 64'b0;
            rmask     <= 8'b0;
            wmask     <= 8'b0;
            csr_wen   <= 1'b0;
            csr_rdata <= 'b0;
            pre_pc    <= 'b0;
            pre_jump  <= 'b0;
            stop      <= 'b0;
        end
        else begin
            stop      <= ex_ready;
            if (id2ex_valid&&ex_ready) begin
                pc        <= i_pc ;
                inst      <= i_inst ;
                reg_waddr <= i_reg_waddr ;
                src1      <= i_src1 ;
                src2      <= i_src2 ;
                RegWr     <= i_RegWr ;
                ALUAsrc   <= i_ALUAsrc ;
                ALUBsrc   <= i_ALUBsrc ;
                ALUctr    <= i_ALUctr ;
                Branch    <= i_Branch ;
                MemtoReg  <= i_MemtoReg ;
                MemWr     <= i_MemWr ;
                imm       <= i_imm ;
                rmask     <= i_rmask ;
                wmask     <= i_wmask ;
                pre_pc    <= i_pre_pc ;
                pre_jump  <= i_pre_jump ;
                csr_wen   <= i_csr_wen ;
                csr_rdata <= (o_csr_wen&&(i_imm[11:0]==o_csr_waddr))?o_csr_wdata: i_csr_rdata ;
            end
            else begin
                if (!id2ex_valid) begin
                    pc        <= 32'b0;
                    inst      <= 32'b0;
                    reg_waddr <= 5'b0;
                    src1      <= 'b0;
                    src2      <= 'b0;
                    RegWr     <= 1'b0;
                    ALUAsrc   <= 1'b0;
                    ALUBsrc   <= 3'b0;
                    ALUctr    <= 6'b0;
                    Branch    <= 3'b0;
                    MemtoReg  <= 1'b0;
                    MemWr     <= 1'b0;
                    imm       <= 64'b0;
                    rmask     <= 8'b0;
                    wmask     <= 8'b0;
                    pre_pc    <= 'b0;
                    pre_jump  <= 'b0;
                    csr_wen   <= 1'b0; 
                    csr_rdata <= 'b0;
                end
             
            end
        end
    end

    
    wire [63:0] op1;
    reg  [63:0] op2;
    wire [63:0] res;
    wire fence_i;
    reg  fence_flag;
    assign fence_i        = o_inst  == `ysyx_050369_FENCE;
    assign o_ex_fence_i   = {fence_i , fence_flag};
    always @(posedge clk) begin
        if (rst) begin
            fence_flag <= 1'b0;
        end
        else begin
            if (fence_i) begin
                fence_flag <= 1'b1;
            end
            else if(i_dcache_done) begin
                fence_flag <= 1'b0;
            end
        end
    end

    assign op1           = (inst[6:0]==`ysyx_050369_TYPE_CSR)?csr_rdata: (ALUAsrc?{32'b0,pc}:src1);
    assign o_reg_wen     = RegWr;
    assign o_reg_waddr   = reg_waddr;
    assign o_reg_res     = csr_wen?csr_rdata: res;
    assign o_csr_wen     = csr_wen;
    assign o_csr_waddr   = imm[11:0];
    assign o_csr_wdata   = res;
    assign o_nxpc        = nxpc;
    assign o_jump_valid  = jump_valid;
    assign o_mem_wen     = MemWr;
    assign o_mem_waddr   = res [31:0];
    assign o_mem_wdata   = src2 ;
    assign o_mem_wmask   = wmask;
    assign o_mem_ren     = MemtoReg;
    assign o_mem_raddr   = res[31:0];
    assign o_mem_rmask   = rmask;
    assign o_pc          = pc;
    assign o_inst        = inst;
    assign o_ecall_flag  = inst==`ysyx_050369_ECALL;
    assign o_mret_flag   = inst==`ysyx_050369_MRET;
    always @(*) begin
        case (ALUBsrc)
            3'b000 : op2 = src2;
            3'b001 : op2 = imm;
            3'b010 : op2 = 64'h4;
            3'b011 : op2 = {59'b0,inst[19:15]};
            3'b100 : op2 = csr_rdata;
            3'b101 : op2 = src1;
            default: op2 = 'b0;
        endcase
    end
    ysyx_050369_alu   alu(
        .clk        (clk),
        .rst        (rst),
        .op1        (op1),
        .op2        (op2),
        .stop       (stop),
        .ALUctr     (ALUctr),
        .ALU_busy   (o_ALU_busy),
        .res        (res)
    );
    ysyx_050369_next_pc nxtpc(
        .rst        (rst),
        .Branch     (Branch),
        .pc         (pc),
        .imm        (imm[31:0]),
        .src1       (src1[31:0]),
        .res        (res),
        .nxpc       (nxpc),
        .jump_valid (jump_valid)
    );

    assign pre_error = (jump_valid != pre_jump)||jump_valid&&(nxpc!=pre_pc);
`ifndef ysyx_050369_SOC
    import "DPI-C" function void set_break(input reg [63:0] a0) ;
    always @(*) begin
        if(inst == `ysyx_050369_EBREAK) begin
            set_break(src1);
        end
    end
`endif
endmodule